﻿using System;
using System.Collections.Generic;
using System.IO;
using FNN.CustomFunctions;
using FNN.Helpers;
using FNN.NetworkMasters;
using FNN.Networks;
using FNN.SourcePoints;
using FNN.Models.Operations;

namespace FinancialNeuronNetwork
{
    internal class Program
    {
        private static readonly FinancialNetworkMaster Master = new FinancialNetworkMaster();
        private static FinancialNetwork _currentNetwork;

        public static CsvHelper Helper { get; set; }

        private static List<SourcePoint> GetDataSource(string pathToData)
        {
            Helper = new FinancialCsvHelper(pathToData);
            var initialData = Helper.GetBody();
            var dataHeaders = Helper.GetHeader();
            var result = Helper.ProcessData(dataHeaders, initialData);
            return result;
        }

        private static void ShowResultsImprovedMessage(double result, int operationCount)
        {
            Console.WriteLine("Результат сети улучшился. Текущий результат: " + result);
            Console.WriteLine("Текущее количество операций: " + operationCount);
        }

        private static void Main(string[] args)
        {
            var serializationHelper = new SerializationHelper();
            if (args.Length > 0)
            {
                if (args[0].ToLower().Contains("train"))
                {
                    var settingsPath = args[1];
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<TrainingModel>(settingsPath);
                    
                    _currentNetwork = (FinancialNetwork) serializationHelper.LoadBinary(model.NetworkName + ".fnn");
                    if (_currentNetwork == null)
                    {
                        Console.WriteLine("Ошибка! Файл поврежден или имел неверный формат!");
                        return;
                    }

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.TimeLimit = model.TimeLimit;
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.ProfitPercent = model.ProfitPercent;
                    Master.PopulationCount = 10;

                    Console.WriteLine("Обучаем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (args[0].ToLower().Contains("create"))
                {
                    var settingsPath = args[1];
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<CreationModel>(settingsPath);       

                    _currentNetwork = new FinancialNetwork(model.InputCount, model.LayersCount, model.LayerSize,
                        new List<FunctionTypes> { model.FunctionType }, model.OutputsCount);

                    _currentNetwork.NetworkName = model.NetworkName;

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.TimeLimit = model.TimeLimit;
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.ProfitPercent = model.ProfitPercent;
                    Master.PopulationCount = 10;

                    Console.WriteLine("Обучаем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть создана и обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (args[0].ToLower().Contains("cultivate"))
                {
                    var settingsPath = args[1];
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<CultivationModel>(settingsPath);

                    _currentNetwork = new FinancialNetwork(model.InputCount, model.LayersCount, model.LayerSize,
                        new List<FunctionTypes> { model.FunctionType }, model.OutputsCount);

                    _currentNetwork.NetworkName = model.NetworkName;

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.TimeLimit = model.TimeLimit;
                    Master.PopulationCount = model.PopulationCount;
                    Master.GeneticIterationsLimit = model.GeneticIterationsLimit;
                    Master.GeneticTimeLimit = model.GeneticTimeLimit;
                    Master.GeneticProfitPercent = model.GeneticResult;

                    Console.WriteLine("Обучаем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.NetworkCultivation(_currentNetwork, true);
                    Console.WriteLine("Сеть культивирована, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (args[0].ToLower().Contains("help"))
                {
                    if (!File.Exists("readme.txt")) return;
                    Console.Clear();
                    var helpFile = File.ReadAllLines("readme.txt");
                    foreach (var row in helpFile)
                    {
                        Console.WriteLine(row);
                    }
                }
                else
                {
                    Console.WriteLine("Некорректные аргументы!");
                }
            }
            else
            {
                Console.WriteLine("Вас приветствует мастер по созданию и обучению сети");
                Console.Write("Что бы Вы хотели сделать (create/train/cultivate): ");
                var action = Console.ReadLine() ?? "";
                if (action.ToLower().Contains("train"))
                {
                    Console.Write("Путь к настройкам: ");
                    var settingsPath = Console.ReadLine();
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<TrainingModel>(settingsPath);

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.TimeLimit = model.TimeLimit;
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.ProfitPercent = model.ProfitPercent;
                    Master.PopulationCount = 10;

                    _currentNetwork = (FinancialNetwork) serializationHelper.LoadBinary(model.NetworkName + ".fnn");
                    if (_currentNetwork == null)
                    {
                        Console.WriteLine("Ошибка! Файл поврежден или имел неверный формат!");
                        return;
                    }
                    Console.WriteLine("Обучаем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (action.ToLower().Contains("create"))
                {
                    Console.Write("Путь к настройкам: ");
                    var settingsPath = Console.ReadLine();
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<CreationModel>(settingsPath);


                    _currentNetwork = new FinancialNetwork(model.InputCount, model.LayersCount, model.LayerSize,
                        new List<FunctionTypes> { model.FunctionType }, model.OutputsCount);
                    _currentNetwork.NetworkName = model.NetworkName;

                    Console.WriteLine("Cеть создана...");

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.TimeLimit = model.TimeLimit;
                    Master.PopulationCount = 10;

                    Console.WriteLine("Обучаем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.TrainMultiNetwork(_currentNetwork);
                    Console.WriteLine("Сеть создана и обучена, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
                else if (action.ToLower().Contains("cultivate"))
                {
                    Console.Write("Путь к настройкам: ");
                    var settingsPath = Console.ReadLine();
                    if (!File.Exists(settingsPath))
                    {
                        Console.WriteLine("Файл с настройками не найден!");
                        return;
                    }
                    var model = serializationHelper.ParseJson<CultivationModel>(settingsPath);


                    _currentNetwork = new FinancialNetwork(model.InputCount, model.LayersCount, model.LayerSize,
                        new List<FunctionTypes> { model.FunctionType }, model.OutputsCount);
                    _currentNetwork.NetworkName = model.NetworkName;

                    Master.DataSource = GetDataSource(model.DataPath);
                    Master.IterationsLimit = model.IterationsLimit;
                    Master.TimeLimit = model.TimeLimit;
                    Master.PopulationCount = model.PopulationCount;
                    Master.GeneticIterationsLimit = model.GeneticIterationsLimit;
                    Master.GeneticTimeLimit = model.GeneticTimeLimit;
                    Master.GeneticProfitPercent = model.GeneticResult;

                    Console.WriteLine("Культивируем сеть...");
                    Master.ResultsImprovedWithCount += ShowResultsImprovedMessage;

                    var result = Master.NetworkCultivation(_currentNetwork, true);
                    Console.WriteLine("Сеть культивирована, записываем в файл...");

                    serializationHelper.WriteBinary(result, model.NetworkName + ".fnn");
                    Console.WriteLine("Готово!");
                }
            }
            Console.ReadKey();
        }
    }
}